package ca.etsmtl.log540.tp3;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TimeClient {

    private static final int FUDGE_FACTOR = 42 * 1337;
        
        static final int PORT = 1337;
        static final String HOST ="127.0.0.1";
        static private long requestToServerTimeStamp;      
        private long offSet;

	// L'heure sur le client est brisée! Vous devez obtenir le temps uniquement
    // avec cette méthode
    public static long getClientTime() {
        return System.currentTimeMillis() - FUDGE_FACTOR;
    }

	// Vous pouvez utiliser cette méthode pour vérifier vos résultats
	public static void report(long mauvaiseHeureClient, long estimeHeure,
			long offset) {
		System.out.println("Mauvaise heure: " + new Date(mauvaiseHeureClient));
		System.out.println("Estimé de la bonne heure: " + new Date(estimeHeure));
		System.out.println("Vrai heure: "
				+ new Date(System.currentTimeMillis()));
	}

    public static void main(String[] args) {
        new TimeClient().run();
    }

	void run() {
                EventLoopGroup group = new NioEventLoopGroup();
                try {
                    Bootstrap b = new Bootstrap();
                    b.group(group)
                     .channel(NioDatagramChannel.class)
                     .option(ChannelOption.SO_BROADCAST, true)
                     .handler(new TimeClientHandler());

                    Channel ch = b.bind(0).sync().channel();
                    requestToServerTimeStamp = getClientTime();
                    // Broadcast the  request to port .
                    ch.writeAndFlush(new DatagramPacket(
                            Unpooled.copiedBuffer("HEURE?", CharsetUtil.UTF_8),
                            new InetSocketAddress(HOST, PORT))).sync();

                    // will close the DatagramChannel when a
                    // response is received.  If the channel is not closed within 5 seconds,
                    // print an error message and quit.
                    if (!ch.closeFuture().await(5000)) {
                        System.err.println("HEURE requete");
                    }
                } catch (InterruptedException ex) {
                Logger.getLogger(TimeClient.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                    group.shutdownGracefully();
                }
	}

    static class TimeClientHandler extends
            SimpleChannelInboundHandler<DatagramPacket> {

		@Override
		protected void channelRead0(ChannelHandlerContext ctx,
				DatagramPacket packet) throws Exception {
                    
                    String response = packet.content().toString(CharsetUtil.UTF_8);
                    String time = "HEURE: ";
                    if (response.startsWith("HEURE: ")) {
                        System.out.println("Time at the Moment: " + response.substring(time.length()));
                        long responseFromServerTimeStamp = getClientTime();
                        long offset = (responseFromServerTimeStamp-requestToServerTimeStamp)/2;
                        report(getClientTime(),Long.parseLong(response.substring(time.length()),10)+offset,
			offset);
                        ctx.close();
                    }
			// TODO Exercice #5
		}

    }

}
